/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.web.service.support.storage;

import org.springframework.stereotype.Service;
import org.vacoor.nothing.web.service.FileStorageService;
import org.vacoor.nothing.common.codec.Base64;
import org.vacoor.nothing.common.util.Bytes;
import org.vacoor.nothing.common.util.IOUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 最简单的文件存储
 * 不进行 Hash 校验
 * <p/>
 *
 * @author vacoor
 */
@Service
public class FileLocalStorageServiceImpl extends DailyRollingStorageService implements FileStorageService {
    public static final String ENCODE_PREFIX = "FLS";
    public static final String ENCODE_SEPARATOR = "!!";

    public FileLocalStorageServiceImpl() {
        setStorageHome(getStorageHome() + "/files");
    }

    @Override
    public File readAsFile(String id) {
        File file = new File(getStorageRealPath(decodePath(id)));
        return file.exists() ? file : null;
    }

    @Override
    public String store(InputStream is) throws IOException {
        File path = new File(getStorageRealPath(getDailyRollingFolder()));
        if (!path.exists()) {
            path.mkdirs();
        }

        File file = new File(path, generateFilename());
        try {
            IOUtils.flow(is, new FileOutputStream(file), true, true);
        } catch (IOException ioe) {
            file.delete();
            throw ioe;
        }

        return encodePath(getStorageRelativePath(file.getAbsolutePath()));
    }

    /**
     * encode given file path
     *
     * @param path
     * @return
     */
    private String encodePath(String path) {
        path = !path.endsWith("/") ? path : path.substring(0, path.length() - 1);

        int i = path.lastIndexOf("/");
        if (-1 < i) {
            path = Base64.encodeToUrlSafeString(Bytes.toBytes(path.substring(0, i))) + ENCODE_SEPARATOR + path.substring(i + 1);
        }
        return ENCODE_PREFIX + path;
    }

    /**
     * decode {@link #encodePath(String)}
     *
     * @param encodedPath
     * @return
     */
    private String decodePath(String encodedPath) {
        int i = encodedPath.indexOf(ENCODE_SEPARATOR);
        if (-1 < i && encodedPath.startsWith(ENCODE_PREFIX)) {
            String fname = encodedPath.substring(i + 2);
            encodedPath = encodedPath.substring(ENCODE_PREFIX.length(), i); // ignore F
            encodedPath = Bytes.toString(Base64.decode(encodedPath, true)) + "/" + fname;
        }
        return encodedPath;
    }
}
